/*
 * Copyright (C) 2025 Tsingteng MicroSystem
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#include "wiredse_main.h"
#include "nfa_wiredse_api.h"
#include "nfa_base.h"
#include "nci_module.h"
#include "hci_transport.h"
#include "hci_defs.h"
#include "nfc_osi_api.h"
#include "nci_feature.h"
#include "nfc_config_api.h"

/**
 * @brief wiredse状态机处理，数据分发
 */

#if IS_FEATURE_ON(NCI_FEATURE_WIRED_SE)
static void apdu_pipe_data_handler(uint8_t pipe, const uint8_t *data, uint16_t data_len);
static void wiredse_update_state(tWIREDSE_STATE new_state);

tMUTEX g_wiredse_lock = MUTEX_INIT_VAL("wiredse");
tWIREDSE_RESULT g_wiredse_result;
static tWIREDSE_STATE g_wiredse_state = WIREDSE_STATE_IDLE;
tAPDU last_ATR;
tWIREDSE_PROP wiredse_prop = {
    .max_rapdu_wait_time = 30000, // 等待APDU超时时间，默认30S
};

/**
 * @brief wiredse模块初始化
 */
static tNCI_STATUS nfa_wiredse_init(const tNCI_MODULE_INIT_CFG *p_cfg) {
    (void)p_cfg;
    tNCI_STATUS status;
    tNFC_STATUS nfc_status;
    nfc_status = osi_mutex_init(&g_wiredse_lock);
    if (NFC_STATUS_OK != nfc_status) {
        NFCLOG_E("init mutex for wiredse failed");
        status = NCI_STATUS_EXT_GET_LOCK_FAILED;
        goto exit;
    }
    const tNFC_CF *cf = nfc_config_get();
    if (cf) {
        wiredse_prop.max_rapdu_wait_time = cf->max_rapdu_wait_time;
        NFCLOG_D("max rapdu wait time:%dms", wiredse_prop.max_rapdu_wait_time);
    } else {
        NFCLOG_W("get cfg fail");
    }
    status = hci_transport_register_pipe_event_handler(HCI_DYNAMIC_PIPE_APDU, apdu_pipe_data_handler);
    if (NCI_STATUS_OK != status) {
        NFCLOG_E("register apdu pipe data callback failed");
        goto clean;
    }
    // 当前上层Terminal在获取AC规则时，不会先open wiredse，所以先把状态机置成opened状态
    // wiredse_update_state(WIREDSE_STATE_IDLE);
    wiredse_update_state(WIREDSE_STATE_OPENED);
    return status;
clean:
    nfc_status = osi_mutex_deinit(&g_wiredse_lock);
    if (NFC_STATUS_OK != nfc_status) {
        NFCLOG_E("deinit mutex for wiredse failed");
    }
exit:
    wiredse_update_state(WIREDSE_STATE_INIT);
    return status;
}

/**
 * @brief nfa_wiredse_deinit
 */
static tNCI_STATUS nfa_wiredse_deinit(bool is_shutdown) {
    (void)is_shutdown;
    tNCI_STATUS status;
    tNFC_STATUS nfc_status;
    status = hci_transport_register_pipe_event_handler(HCI_DYNAMIC_PIPE_APDU, NULL);
    if (NCI_STATUS_OK != status) {
        NFCLOG_E("unregister apdu pipe data callback failed");
    }
    nfc_status = osi_mutex_lock(&g_wiredse_lock);
    if (NFC_STATUS_OK != nfc_status) {
        NFCLOG_E("deinit mutex for wiredse failed");
        status = NCI_STATUS_EXT_GET_LOCK_FAILED;
        goto exit;
    }
    wiredse_update_state(WIREDSE_STATE_INIT);
    // 清空ATR缓存
    if (last_ATR.data) {
        osi_free(last_ATR.data);
        last_ATR.data = NULL;
        last_ATR.len = 0;
    }
    // 回收未被处理的执行结果
    wiredse_clean_result();
    // 唤醒所有等待的线程
    nfc_status = osi_mutex_notify_all(&g_wiredse_lock);
    if (NFC_STATUS_OK != nfc_status) {
        NFCLOG_E("deinit mutex for wiredse failed");
        status = NCI_STATUS_EXT_GET_LOCK_FAILED;
        goto exit;
    }
    nfc_status = osi_mutex_unlock(&g_wiredse_lock);
    if (NFC_STATUS_OK != nfc_status) {
        NFCLOG_E("deinit mutex for wiredse failed");
        status = NCI_STATUS_EXT_GET_LOCK_FAILED;
        goto exit;
    }
    nfc_status = osi_mutex_deinit(&g_wiredse_lock);
    if (NFC_STATUS_OK != nfc_status) {
        NFCLOG_E("deinit mutex for wiredse failed");
        status = NCI_STATUS_EXT_GET_LOCK_FAILED;
    }
exit:
    return status;
}

/**
 * @brief 异步往apdu pipe发送event
 * @note 如果credit不足时，会阻塞等待
 * @param event 要发送的event
 * @param data event待的data内容
 * @param data_len data段长度
 * @return 成功时返回NCI_STATUS_OK
 */
static tNCI_STATUS send_apdu_pipe_event_async(uint8_t event, const uint8_t *data, uint16_t data_len) {
    return hci_send_hcp_message_async(HCI_DYNAMIC_PIPE_APDU, HCI_HCP_TYPE_EVENT, event, data_len, data);
}

/**
 * @brief apdu pipe数据回调，分发
 * @note 接收从hci模块分发的pipe数据，解析event类型后送往状态机处理
 * @param pipe 数据来源pipe
 * @param data
 * @param data_len
 */
static void apdu_pipe_data_handler(uint8_t pipe, const uint8_t *data, uint16_t data_len) {
    if (HCI_DYNAMIC_PIPE_APDU != pipe) {
        NFCLOG_W("data not from apdu pipe");
        return;
    }
    if ((NULL == data) || (data_len < 1)) {
        NFCLOG_E("got invaild apdu event");
        return;
    }
    uint8_t event = data[0] & HCI_INS_MASK;
    tNCI_STATUS status;
    switch (event) {
    case HCI_EVT_R_APDU:
        NFCLOG_D("rapdu got. len:%d", data_len - 1);
        tWIREDSE_MESSAGE_CONTENT rapdu;
        rapdu.apdu.data = osi_malloc(data_len - 1);
        if (NULL == rapdu.apdu.data) {
            NFCLOG_E("malloc failed for rapdu");
            break;
        }
        if (!osi_memcpy_s(rapdu.apdu.data, data_len - 1, data + 1, data_len - 1)) {
            NFCLOG_E("memcpy failed");
            osi_free(rapdu.apdu.data);
            rapdu.apdu.data = NULL;
            break;
        }
        rapdu.apdu.len = data_len - 1;
        status = wiredse_sm(WIREDSE_EVT_RECV_APDU, &rapdu);
        if (NCI_STATUS_OK != status) {
            NFCLOG_E("wiredse sm reject rapdu packet. ret:%d", status);
            osi_free(rapdu.apdu.data);
            rapdu.apdu.data = NULL;
        }
        break;
    case HCI_EVT_ATR:
        NFCLOG_D("ATR got. len:%d", data_len - 1);
        tWIREDSE_MESSAGE_CONTENT atr;
        atr.atr.data = osi_malloc(data_len - 1);
        if (NULL == atr.atr.data) {
            NFCLOG_E("malloc failed for atr");
            break;
        }
        if (!osi_memcpy_s(atr.atr.data, data_len - 1, data + 1, data_len - 1)) {
            NFCLOG_E("memcpy failed");
            osi_free(atr.atr.data);
            atr.atr.data = NULL;
            break;
        }
        atr.atr.len = data_len - 1;
        status = wiredse_sm(WIREDSE_EVT_RECV_ATR, &atr);
        if (NCI_STATUS_OK != status) {
            NFCLOG_E("wiredse sm reject atr packet. ret:%d", status);
            osi_free(atr.atr.data);
            atr.atr.data = NULL;
        }
        break;
    case HCI_EVT_WTX:
        NFCLOG_D("WTX got. len:%d", data_len - 1);
        status = wiredse_sm(WIREDSE_EVT_RECV_WTX, NULL);
        if (NCI_STATUS_OK != status) {
            NFCLOG_E("wiredse sm reject wtx packet. ret:%d", status);
        }
        break;
    default:
        NFCLOG_E("unknown apdu event:%02X", event);
        break;
    }
}

/**
 * @brief wiredse状态机
 * @note 事件开始处理时会持有g_wiredse_lock锁
 *       如果是指令请求类型(abort、end apdu、发送apdu)，并且请求被状态机正确处理了，
 *       g_wiredse_lock锁不会被释放，请求方继续使用这个锁等待执行结果。
 *
 *       指令被拒绝/不处理，处理发生错误，还有其他请求被处理完成后g_wiredse_lock都会被释放
 *
 *       操作返回NCI_STATUS_OK时，content内容由本方法进行回收或者传给对应的回调方法
 *       返回其他值时，请求方需要把content的内存进行回收
 *       例外：WIREDSE_EVT_SEND_APDU的内容可能来自常量或者栈内存，故不做回收处理，由调用方回收
 *
 *       开始处理事件时会检查是否有事件处理结果未被处理
 *       如果有未处理的事件会直接把对应资源进行回收
 *
 *       事件被处理完成时，如果有结果需要返回，会存放在g_wiredse_result中，
 *       处理结果前需要等待到对应的事件并持有g_wiredse_lock，处理完成并销毁结果的内存后再释放锁
 * @param event 发生的事件
 * @param content event内容
 * @return 事件被成功处理返回NCI_STATUS_OK
 *         事件被拒绝/不处理返回NCI_STATUS_EXT_REJECTED
 */
tNCI_STATUS wiredse_sm(tWIREDSE_EVENT event, tWIREDSE_MESSAGE_CONTENT *content) {
    tNCI_STATUS status = NCI_STATUS_EXT_REJECTED;
    NFCLOG_D("got event:%d", event);
    if (NFC_STATUS_OK != osi_mutex_lock(&g_wiredse_lock)) {
        NFCLOG_E("get wiredse mutex failed");
        return NCI_STATUS_EXT_GET_LOCK_FAILED;
    }
    NFCLOG_D("handle event:%d in state:%d", event, g_wiredse_state);
    // 先检查是否有未处理的result
    wiredse_clean_result();
    switch (g_wiredse_state) {
    case WIREDSE_STATE_INIT:
        // 未初始化状态，不处理任何消息
        break;
    case WIREDSE_STATE_IDLE:
        switch (event) {
        case WIREDSE_EVT_ABORT:
            status = send_apdu_pipe_event_async(HCI_EVT_ABORT, NULL, 0);
            if (NCI_STATUS_OK == status) {
                wiredse_update_state(WIREDSE_STATE_OPENNING);
                goto exit; // 发送指令成功，跳过释放锁
            }
            break;
        default:
            // 其他event均不处理
            break;
        }
        break;
    case WIREDSE_STATE_OPENNING:
        switch (event) {
        case WIREDSE_EVT_RECV_ATR:
            if (NULL == content) {
                NFCLOG_E("missing param");
                status = NCI_STATUS_EXT_INVALID_PARAM;
            } else {
                wiredse_update_state(WIREDSE_STATE_OPENED);
                g_wiredse_result.event = event;
                g_wiredse_result.content.atr = content->atr;
                // data内存转给结果，给请求方标记为内存已释放
                content->atr.data = NULL;
                status = NCI_STATUS_OK;
            }
            break;
        case WIREDSE_EVT_ABORT:
            status = send_apdu_pipe_event_async(HCI_EVT_ABORT, NULL, 0);
            if (NCI_STATUS_OK == status) {
                wiredse_update_state(WIREDSE_STATE_OPENNING);
                goto exit; // 发送指令成功，跳过释放锁
            }
            break;
        case WIREDSE_EVT_TIMEOUT:
            wiredse_update_state(WIREDSE_STATE_IDLE);
            g_wiredse_result.event = WIREDSE_EVT_UNKNOWN;
            status = NCI_STATUS_OK;
            break;
        default:
            // 其他event均不处理
            break;
        }
        break;
    case WIREDSE_STATE_OPENED:
        switch (event) {
        case WIREDSE_EVT_ABORT:
            status = send_apdu_pipe_event_async(HCI_EVT_ABORT, NULL, 0);
            if (NCI_STATUS_OK == status) {
                wiredse_update_state(WIREDSE_STATE_OPENNING);
                goto exit; // 发送指令成功，跳过释放锁
            }
            break;
        case WIREDSE_EVT_END_APDU:
            status = send_apdu_pipe_event_async(HCI_EVT_END_OF_APDU_TRANSFER, NULL, 0);
            if (NCI_STATUS_OK == status) {
                wiredse_update_state(WIREDSE_STATE_IDLE);
                goto exit; // 发送指令成功，跳过释放锁
            }
            break;
        case WIREDSE_EVT_SEND_APDU:
            if (NULL == content) {
                NFCLOG_E("missing param");
                status = NCI_STATUS_EXT_INVALID_PARAM;
            } else {
                status = send_apdu_pipe_event_async(HCI_EVT_C_APDU, content->apdu.data, content->apdu.len);
                if (NCI_STATUS_OK == status) {
                    // 发APDU事件，参数内存可能来自常量或者栈，跳过参数内存回收
                    wiredse_update_state(WIREDSE_STATE_WAIT_RAPDU);
                    goto exit; // 发送指令成功，跳过释放锁
                }
            }
            break;
        default:
            // 其他event均不处理
            break;
        }
        break;
    case WIREDSE_STATE_WAIT_RAPDU:
        switch (event) {
        case WIREDSE_EVT_RECV_APDU:
            if (NULL == content) {
                NFCLOG_E("missing param");
                status = NCI_STATUS_EXT_INVALID_PARAM;
            } else {
                wiredse_update_state(WIREDSE_STATE_OPENED);
                g_wiredse_result.event = event;
                g_wiredse_result.content.apdu = content->apdu;
                // data内存转给结果，给请求方标记为内存已释放
                content->apdu.data = NULL;
                status = NCI_STATUS_OK;
            }
            break;
        case WIREDSE_EVT_RECV_WTX:
            status = NCI_STATUS_OK;
            break;
        case WIREDSE_EVT_TIMEOUT:
            wiredse_update_state(WIREDSE_STATE_OPENED);
            g_wiredse_result.event = WIREDSE_EVT_UNKNOWN;
            status = NCI_STATUS_OK;
            break;
        default:
            // 其他event均不处理
            break;
        }

        break;
    default:
        break;
    }
    if (WIREDSE_EVT_UNKNOWN != g_wiredse_result.event) {
        // 有结果需要给api层通知
        if (NFC_STATUS_OK != osi_mutex_notify(&g_wiredse_lock)) {
            // notify失败后，释放结果中的内存
            NFCLOG_E("notify wiredse lock failed");
            wiredse_clean_result();
            status = NCI_STATUS_EXT_GET_LOCK_FAILED;
        }
    }
    if (NFC_STATUS_OK != osi_mutex_unlock(&g_wiredse_lock)) {
        NFCLOG_E("unlock wiredse mutex failed");
        wiredse_clean_result();
        status = NCI_STATUS_EXT_GET_LOCK_FAILED;
    }
    if (NCI_STATUS_OK != status) {
        NFCLOG_W("event:%d not handled", event);
    }
exit:
    return status;
}

/**
 * @brief 释放g_wiredse_result中的内存
 * @note 此方法需要再g_wiredse_lock临界区中使用
 */
void wiredse_clean_result(void) {
    if (WIREDSE_EVT_UNKNOWN == g_wiredse_result.event) {
        return;
    }
    // 按照event类型判断content内容，再释放对应的内存
    switch (g_wiredse_result.event) {
    case WIREDSE_EVT_RECV_APDU:
        if (g_wiredse_result.content.apdu.data) {
            osi_free(g_wiredse_result.content.apdu.data);
            g_wiredse_result.content.apdu.data = NULL;
        }
        break;
    case WIREDSE_EVT_RECV_ATR:
        if (g_wiredse_result.content.atr.data) {
            osi_free(g_wiredse_result.content.atr.data);
            g_wiredse_result.content.atr.data = NULL;
        }
        break;
    default:
        NFCLOG_W("unhandle event:%d", g_wiredse_result.event);
        // 其他event的结果中不存在动态的内存
        break;
    }
    // 标记result缓存为空
    g_wiredse_result.event = WIREDSE_EVT_UNKNOWN;
}

/**
 * @brief 更新wiredse状态机状态
 * @note 需要在g_wiredse_lock临界区中调用
 * @param new_state 新状态
 */
static void wiredse_update_state(tWIREDSE_STATE new_state) {
    NFCLOG_I("update wiredse state %d -> %d", g_wiredse_state, new_state);
    g_wiredse_state = new_state;
}

tNCI_MODULE g_wiredse_manager = {
    .name = "WIREDSE",
    .state = NCI_MODULE_STATE_DISABLED,
    .init = nfa_wiredse_init,
    .deinit = nfa_wiredse_deinit,
};

#endif // IS_FEATURE_ON(NCI_FEATURE_WIRED_SE)
